home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1999 August / SGI Freeware 1999 August.iso / dist / fw_geomview.idb / usr / freeware / info / geomview-3.z / geomview-3
Encoding:
Text File  |  1999-01-26  |  66.9 KB  |  1,802 lines

  1. Info file: geomview,    -*-Text-*-
  2. produced by texinfo-format-buffer
  3. from file: geomview.tex
  4.  
  5.  
  6. 
  7. File: geomview  Node: OFF, Prev: BBP and BEZ, Up: Object File Formats, Next: VECT
  8.  
  9. OFF Files
  10. ---------
  11.  
  12. The conventional suffix for `OFF' files is `.off'.
  13.  
  14. Syntax:
  15.  
  16.      [ST][C][N][4][n]OFF    # Header keyword
  17.      [NDIM]        # Space dimension of vertices, present only if nOFF
  18.      NVERTICES  NFACES  NEDGES   # NEdges not used or checked
  19.  
  20.      X[0]  Y[0]  Z[0]    # Vertices, possibly with normals,
  21.                  # colors, and/or texture coordinates, in that order,
  22.                  # if the prefixes `N', `C', `ST'
  23.                  # are present.
  24.                  # If 4OFF, each vertex has 4 components,
  25.                  # including a final homogeneous component.
  26.                  # If nOFF, each vertex has NDIM components.
  27.                  # If 4nOFF, each vertex has NDIM+1 components.
  28.      ...
  29.      X[NVERTICES-1]  Y[NVERTICES-1]  Z[NVERTICES-1]
  30.  
  31.                      # Faces
  32.                      # NV = # vertices on this face
  33.                      # V[0] ... V[NV-1]: vertex indices
  34.                      #        in range 0..NVERTICES-1
  35.      NV  V[0] V[1] ... V[NV-1]  COLORSPEC
  36.      ...
  37.                      # COLORSPEC continues past V[NV-1]
  38.                      # to end-of-line; may be 0 to 4 numbers
  39.                      # nothing: default
  40.                      # integer: colormap index
  41.                      # 3 or 4 integers: RGB[A] values 0..255
  42.                  # 3 or 4 floats: RGB[A] values 0..1
  43.  
  44. `OFF' files (name for "object file format") represent collections
  45. of planar polygons with possibly shared vertices, a convenient way to
  46. describe polyhedra.  The polygons may be concave but there's no
  47. provision for polygons containing holes.
  48.  
  49. An `OFF' file may begin with the keyword `OFF'; it's
  50. recommended but optional, as many existing files lack this keyword.
  51.  
  52. Three ASCII integers follow: NVERTICES, NFACES, and
  53. NEDGES.  Thse are the number of vertices, faces, and edges,
  54. respectively.  Current software does not use nor check NEDGES; it
  55. needn't be correct but must be present.
  56.  
  57. The vertex coordinates follow: dimension * NVERTICES
  58. floating-point values.  They're implicitly numbered 0 through
  59. NVERTICES-1.  dimension is either 3 (default) or 4 (specified by
  60. the key character `4' directly before `OFF' in the keyword).
  61.  
  62. Following these are the face descriptions, typically written
  63. with one line per face.  Each has the form
  64.      N  VERT1 VERT2 ... VERTN  [COLOR]
  65. Here N is the number of vertices on this face,
  66. and VERT1 through VERTN are indices into the list of
  67. vertices (in the range 0..NVERTICES-1).
  68.  
  69. The optional COLOR may take several forms.  Line breaks are
  70. significant here: the COLOR description begins after VERTN
  71. and ends with the end of the line (or the next # comment).  A
  72. COLOR may be:
  73.  
  74. nothing
  75.      the default color
  76. one integer
  77.      index into "the" colormap; see below
  78. three or four integers
  79.      RGB and possibly alpha values in the range 0..255
  80. three or four floating-point numbers
  81.      RGB and possibly alpha values in the range 0..1
  82.  
  83. For the one-integer case, the colormap is currently read from the file
  84. `cmap.fmap' in Geomview's `data' directory.  Some better
  85. mechanism for supplying a colormap is likely someday.
  86.  
  87. The meaning of "default color" varies.  If no face of the object has a
  88. color, all inherit the environment's default material color.  If some
  89. but not all faces have colors, the default is gray (R,G,B,A=.666).
  90.  
  91. A `[ST][C][N][n]OFF BINARY' format is accepted; *Note Binary format::.  It
  92. resembles the ASCII format in almost the way you'd expect, with 32-bit
  93. integers for all counters and vertex indices and 32-bit floats for
  94. vertex positions (and texture coordinates or vertex colors or normals if
  95. `COFF'/`NOFF'/`CNOFF'/`STCNOFF'/etc. format).
  96.  
  97. Exception: each face's vertex indices are followed by an integer
  98. indicating how many color components accompany it.  Face color
  99. components must be floats, not integer values.  Thus a colorless
  100. triangular face might be represented as
  101.  
  102.      int int int int int
  103.      3   17   5   9   0
  104.  
  105. while the same face colored red might be
  106.  
  107.      int int int int int float float float float
  108.       3  17   5   9   4   1.0   0.0   0.0   1.0
  109.  
  110.  
  111. 
  112. File: geomview  Node: VECT, Prev: OFF, Up: Object File Formats, Next: SKEL
  113.  
  114. VECT Files
  115. ----------
  116.  
  117. The conventional suffix for `VECT' files is `.vect'.
  118.  
  119. Syntax:
  120.  
  121.      [4]VECT
  122.      NPOLYLINES  NVERTICES  NCOLORS
  123.  
  124.      NV[0] ... NV[NPOLYLINES-1]     # number of vertices
  125.                                                 # in each polyline
  126.  
  127.      NC[0] ... NC[NPOLYLINES-1]     # number of colors supplied
  128.                                                 # in each polyline
  129.  
  130.      VERT[0] ... VERT[NVERTICES-1]  # All the vertices
  131.                                                 # (3*NVertices floats)
  132.  
  133.      COLOR[0] ... COLOR[NCOLORS-1]  # All the colors
  134.                                                 # (4*NColors floats, RGBA)
  135.  
  136. `VECT' objects represent lists of polylines (strings of connected
  137. line segments, possibly closed).  A degenerate polyline can be used to
  138. represent a point.
  139.  
  140. A `VECT' file begins with the key word `VECT' or `4VECT'
  141. and three integers: NLINES, NVERTICES, and NCOLORS.
  142. Here NLINES is the number of polylines in the file,
  143. NVERTICES the total number of vertices, and NCOLORS the
  144. number of colors as explained below.
  145.  
  146. Next come NLINES integers
  147.  
  148.      NV[0] NV[1] NV[2] ... NV[NLINES-1]
  149.  
  150. giving the number of vertices in each polyline.  A negative number
  151. indicates a closed polyline; 1 denotes a single-pixel point.  The sum
  152. (of absolute values) of the NV[I] must equal NVERTICES.
  153.  
  154. Next come NLINES more integers Nc[i]: the number of colors in
  155. each polyline.  Normally one of three values:
  156.  
  157. 0
  158.      No color is specified for this polyline.  It's drawn in the same color
  159.      as the previous polyline.
  160. 1
  161.      A single color is specified.  The entire polyline is drawn in that
  162.      color.
  163. abs(NV[I])
  164.      Each vertex has a color.  Either each segment is drawn in the
  165.      corresponding color, or the colors are smoothly interpolated along the
  166.      line segments, depending on the implementation.
  167.  
  168. The sum of the NC[I] must equal NCOLORS.
  169.  
  170. Next come NVERTICES groups of 3 or 4 floating-point numbers: the
  171. coordinates of all the vertices.  If the keyword is 4VECT then
  172. there are 4 values per vertex.  The first abs(NV[0]) of them form
  173. the first polyline, the next abs(NV[1]) form the second and so on.
  174.  
  175. Finally NCOLORS groups of 4 floating-point numbers give red,
  176. green, blue and alpha (opacity) values.  The first NC[0] of them
  177. apply to the first polyline, and so on.
  178.  
  179. A VECT BINARY format is accepted; *Note Binary format::.  The
  180. binary format exactly follows the ASCII format, with 32-bit ints where
  181. integers appear, and 32-bit floats where real values appear.
  182.  
  183.  
  184.  
  185. 
  186. File: geomview  Node: SKEL, Prev: VECT, Up: Object File Formats, Next: SPHERE
  187.  
  188. SKEL Files
  189. ----------
  190.  
  191. `SKEL' files represent collections of points and polylines, with
  192. shared vertices.
  193. The conventional suffix for `SKEL' files is `.skel'.
  194.  
  195. Syntax:
  196.  
  197.      [4][n]SKEL
  198.      [NDIM]                    # Vertex dimension, present only if nSKEL
  199.      NVERTICES  NPOLYLINES
  200.  
  201.      X[0]  Y[0]  Z[0]      # Vertices
  202.                          # (if nSKEL, each vertex has NDim components)
  203.      ...
  204.      X[NVERTICES-1]  Y[NVERTICES-1]  Z[NVERTICES-1]
  205.  
  206.                              # Polylines
  207.                              # NV = # vertices on this polyline (1 = point)
  208.                              # V[0] ... V[NV-1]: vertex indices                        #               in range 0..NVERTICES-1
  209.      NV  V[0] V[1] ... V[NV-1]  [COLORSPEC]
  210.      ...
  211.                              # COLORSPEC continues past V[NV-1]
  212.                              # to end-of-line; may be nothing, or 3 or 4 numbers.
  213.                              # nothing: default color
  214.                  # 3 or 4 floats: RGB[A] values 0..1
  215.  
  216. The syntax resembles that of `OFF' files, with a table of vertices
  217. followed by a sequence of polyline descriptions, each referring to vertices
  218. by index in the table.  Each polyline has an optional color.
  219.  
  220. For `nSKEL' objects, each vertex has NDIM components.
  221. For `4nSKEL' objects, each vertex has NDIM+1 components;
  222. the final component is the homogeneous divisor.
  223.  
  224. No `BINARY' format is implemented as yet for `SKEL' objects.
  225.  
  226. 
  227. File: geomview  Node: SPHERE, Prev: SKEL, Up: Object File Formats, Next: INST
  228.  
  229. SPHERE Files
  230. ------------
  231.  
  232. The conventional suffix for `SPHERE' files is `.sph'.
  233.  
  234.      SPHERE
  235.      RADIUS
  236.      XCENTER YCENTER ZCENTER
  237.  
  238. Sphere objects are drawn using rational Bezier patches, which are diced into
  239. meshes; their smoothness, and the time taken to draw them, depends on the
  240. setting of the dicing level, 10x10 by default.
  241. From Geomview, the Appearance panel, the `<N>ad' keyboard command, or
  242. a `dice nu nv' Appearance attribute sets this.
  243.  
  244. 
  245. File: geomview  Node: INST, Prev: SPHERE, Up: Object File Formats, Next: INST Examples
  246.  
  247. INST Files
  248. ----------
  249.  
  250. The conventional suffix for a `INST' file is `.inst'.
  251.  
  252. There is no INST BINARY format.
  253.  
  254. An `INST' applies a 4x4 transformation to another OOGL object.  It
  255. begins with `INST' followed by these sections which may appear in
  256. any order:
  257.      geom OOGL-OBJECT
  258. specifies the OOGL object to be instantiated.  *Note References::, for
  259. the syntax of an OOGL-OBJECT.  The keyword `unit' is a
  260. synonym for `geom'.
  261.      transform   ["{"] `4x4 transform' ["}"]
  262. specifies a single transformation matrix.  Either the
  263. matrix may appear literally as 16 numbers, or there may be
  264. a reference to a "transform" object, i.e.
  265.          "<" file-containing-4x4-matrix
  266. or
  267.          ":" symbol-representing-transform-object>
  268. Another way to specify the transformation is
  269.      transforms
  270.          OOGL-OBJECT
  271. The OOGL-OBJECT must be a `TLIST' object (list of
  272. transformations) object, or a `LIST' whose members are ultimately
  273. `TLIST' objects.  In effect, the `transforms' keyword takes a
  274. collection of 4x4 matrices and replicates the `geom' object, making
  275. one copy for each 4x4 matrix.
  276.  
  277. If no `transform' nor `transforms' keyword appears, no
  278. transformation is applied (actually the identity is applied).  You could
  279. use this for, e.g., wrapping an appearance around an externally-supplied
  280. object, though a single-membered LIST would do this more efficiently.
  281.  
  282. *Note Transformation matrices::, for the matrix format.
  283.  
  284.  
  285. Two more INST fields are accepted: `location' and `origin'.
  286.  
  287.      location [global or camera or ndc or screen or local]
  288. Normally an INST specifies a position relative to its parent object;
  289. the `location' field allows putting an object elsewhere.
  290.    * `location global' attaches the object to the global (a.k.a. universe)
  291.      coordinate system -- the same as that in which geomview's World objects,
  292.      alien geometry, and cameras are placed.
  293.    * `location camera' places the object relative to the camera.
  294.      (Thus if there are multiple views, it may appear in a different 
  295.      spatial position in each view.)  The center of the camera's view
  296.      is along its negative Z axis; positive X is rightward, positive Y upward.
  297.      Normally the units of camera space are the same as global coordinates.
  298.      When a camera is reset, the global origin is at (0,0,-3.0).
  299.    * `location ndc' places the object relative to the normalized unit
  300.      cube into which the camera's projection (perspective or orthographic)
  301.      maps the visible world.  X, Y, and Z are each in the range from -1 to +1,
  302.      with Z = -1 the near and Z = +1 the far clipping plane, and X and Y
  303.      increasing rightward and upward respectively.
  304.      Thus something like
  305.           INST  transform  1 0 0 0  0 1 0 0  0 0 1 0  -.9 -.9 -.999 1
  306.                 location ndc
  307.                 geom < label.vect
  308.      pastes `label.vect' onto the lower left corner of each window,
  309.      and in front of nearly everything else, assuming `label.vect''s
  310.      contents lie in the positive quadrant of the X-Y plane.
  311.      It's tempting to use -1 rather than -.999 as the Z component of the
  312.      position, but that may put the object just nearer than the near clipping
  313.      plane and make it (partially) invisible, due to floating-point error.
  314.    * `location screen' places the object in screen coordinates.
  315.      The range of Z is still -1 through +1 as for ndc coordinates;
  316.      X and Y are measured in pixels, and range from (0,0) at the *lower left*
  317.      corner of the window, increasing rightward and upward.
  318.  
  319. `location local' is the default; the object is positioned relative
  320. to its parent.
  321.  
  322.  
  323.      origin [global or camera or ndc or screen or local] x y z
  324. The `origin' field translates the contents of the INST to
  325. place the origin at the specified point of the given coordinate system.
  326. Unlike `location', it doesn't change the orientation, only the choice
  327. of origin.  Both `location' and `origin' can be used together.
  328.  
  329. So for example
  330.      { INST
  331.        location screen
  332.        origin ndc 0 0 -.99
  333.        geom { < xyz.vect }
  334.        transform { 100 0 0 0  0 100 0 0  0 0 -.009 0   0 0 0 1 }
  335.      }
  336.  
  337. places xyz.vect's origin in the center of the window, just beyond the
  338. near clipping plane.  The unit-length X and Y edges are scaled to be just 100
  339. screen units -- pixels -- long, regardless of the size of the window.
  340.  
  341. * Menu:
  342.  
  343. * INST Examples::    Some example of `INST' Files.
  344.  
  345. 
  346. File: geomview  Node: INST Examples, Prev: INST, Up: Object File Formats, Next: LIST
  347.  
  348. INST Examples
  349. .............
  350.  
  351. Here are some examples of `INST' files
  352.  
  353.      INST
  354.           unit < xyz.vect
  355.           transform {
  356.              1 0 0 0
  357.              0 1 0 0
  358.              0 0 1 0
  359.              1 3 0 1
  360.           }
  361.  
  362.      { appearance { +edge  material { edgecolor 1 1 0 } }
  363.          INST geom < mysurface.quad }
  364.  
  365.      {INST transform {: T} geom {<dodec.off}}
  366.  
  367.      { INST
  368.           transforms
  369.               { LIST
  370.               { < some-matrices.prj }
  371.               { < others.prj }
  372.               { TLIST <still more of them> }
  373.          
  374.               }
  375.           geom
  376.               { # stuff replicated by all the above matrices
  377.               ...
  378.               }
  379.      }
  380.  
  381. This one resembles the `origin' example in the section above,
  382. but makes the X and Y edges be 1/4 the size of the window (1/4, not 1/2,
  383. since the range of ndc X and Y coordinates is -1 to +1).
  384.      { INST
  385.        location ndc
  386.        geom { < xyz.vect }
  387.        transform { .5 0 0 0  0 .5 0 0  0 0 -.009 0   0 0 -.99 1 }
  388.      }
  389. 
  390. File: geomview  Node: LIST, Prev: INST Examples, Up: Object File Formats, Next: TLIST
  391.  
  392. LIST Files
  393. ----------
  394.  
  395. The conventional suffix for a `LIST' file is `.list'.
  396.  
  397. A list of OOGL objects
  398.  
  399. Syntax:
  400.  
  401.      LIST
  402.          OOGL-OBJECT
  403.          OOGL-OBJECT
  404.          ...
  405.  
  406. Note that there's no explicit separation between the oogl-objects, so
  407. they should be enclosed in curly braces ({ }) for sanity.  Likewise
  408. there's no explicit marker for the end of the list; unless appearing
  409. alone in a disk file, the whole construct should also be wrapped in
  410. braces, as in:
  411.  
  412.         { LIST { QUAD ... } { < xyz.quad } }
  413.  
  414. A `LIST' with no elements, i.e. `{ LIST }', is valid, and is
  415. the easiest way to create an empty object.  For example, to remove a
  416. symbol's definition you might write
  417.  
  418.         { define somesymbol  { LIST } }
  419.  
  420.  
  421. 
  422. File: geomview  Node: TLIST, Prev: LIST, Up: Object File Formats, Next: GROUP
  423.  
  424. TLIST Files
  425. -----------
  426.  
  427.  
  428. The conventional suffix for a `TLIST' file is `.grp' ("group")
  429. or or `.prj' ("projective" matrices).
  430.  
  431. Collection of 4x4 matrices, used in the `transforms' section of and
  432. `INST' object.
  433.  
  434. Syntax:
  435.  
  436.      TLIST            # key word
  437.  
  438.      <4x4 matrix (16 floats)>
  439.      ...                # Any number of 4x4 matrices
  440.  
  441. `TLIST's are used only within the `transforms' clause of an
  442. `INST' object.  They cause the `INST's `geom' object to
  443. be instantiated once under each of the transforms in the `TLIST'.
  444. The effect is like that of a `LIST' of `INST's each with a
  445. single transform, and all referring to the same object, but is more
  446. efficient.
  447.  
  448. Be aware that a `TLIST' is a kind of geometry object, distinct from a 
  449. `transform' object.  Some contexts expect one type of object,
  450. some the other.  For example in
  451.      INST transform { : MYT } geom { ... }
  452. MYT must be a transform object, which might have been
  453. created with the gcl
  454.      (read transform { define myT 1 0 0 1 ... })
  455. while in
  456.          INST transforms { : MYTS } geom { ... }
  457.      or  INST transforms { LIST {: MYTS} {< more.prj} } geom { ... }
  458. MYTS must be a geometry object, defined e.g. with
  459.          (read geometry { define MYTS { TLIST 1 0 0 1 ... } })
  460.  
  461. A `TLIST BINARY' format is accepted.  Binary data begins with a
  462. 32-bit integer giving the number of transformations, followed by that
  463. number of 4x4 matrices in 32-bit floating-point format.  The order of
  464. matrix elements is the same as in the ASCII format.
  465.  
  466.  
  467. 
  468. File: geomview  Node: GROUP, Prev: TLIST, Up: Object File Formats, Next: DISCGRP
  469.  
  470. GROUP Files
  471. -----------
  472.  
  473. This format is obsolete, but is still accepted.  It combined the
  474. functions of `INST' and `TLIST', taking a series of
  475. transformations and a single Geom (`unit') object, and replicating
  476. the object under each transformation.
  477.  
  478.      GROUP ... < matrices > ... unit { OOGL-OBJECT }
  479.  
  480. is still accepted and effectively translated into
  481.  
  482.      INST
  483.          transforms { TLIST ... <matrices> ... }
  484.          unit { OOGL-OBJECT }
  485.  
  486. 
  487. File: geomview  Node: DISCGRP, Prev: GROUP, Up: Object File Formats, Next: COMMENT
  488.  
  489. DISCGRP Files
  490. -------------
  491.  
  492. This format is for discrete groups, such as appear in the theory of
  493. manifolds or in symmetry patterns.  This format has its own man page.
  494. See discgrp(5).
  495.  
  496. 
  497. File: geomview  Node: COMMENT, Prev: DISCGRP, Up: Object File Formats, Next: Non-geometric objects
  498.  
  499. COMMENT Objects
  500. ---------------
  501.  
  502. The COMMENT object is a mechanism for encoding arbitrary data within an
  503. OOGL object. It can be used to keep track of data or pass data back and
  504. forth between external modules. 
  505.  
  506. Syntax:
  507.  
  508.      COMMENT                 # key word
  509.             
  510.      NAME TYPE   # individual name and type specifier
  511.      { ... }             # arbitrary data
  512.  
  513. The data, which must be enclosed by curly braces, can include anything
  514. except unbalanced curly braces.  The TYPE field can be used to
  515. identify data of interest to a particular program through naming
  516. conventions. 
  517.  
  518. `COMMENT' objects are intended to be associated with other objects
  519. through inclusion in a `LIST' object. (*Note LIST::.)  The "#" OOGL
  520. comment syntax does not suffice for data exchange since these comments
  521. are stripped when an OOGL object is read in to Geomview.  The
  522. `COMMENT' object is preserved when loaded into Geomview and is
  523. written out intact.
  524.  
  525. Here is an example associating a WorldWide Web URL with a piece of
  526. geometry:
  527.  
  528.      { LIST 
  529.       { < Tetrahedron} 
  530.       {COMMENT GCHomepage HREF { http://www.geom.umn.edu/ }}
  531.      }
  532.  
  533. A binary `COMMENT' format is accepted. Its format is not consistent
  534. with the other OOGL binary formats. *Note Binary format::. The
  535. `name' and `type' are followed by
  536.  
  537.      N BYTE1 BYTE2 ... BYTEN
  538.  
  539. instead of data enclosed in curly braces. 
  540.  
  541. 
  542. File: geomview  Node: Non-geometric objects, Prev: COMMENT, Up: OOGL File Formats, Next: transform
  543.  
  544. Non-geometric objects
  545. =====================
  546.  
  547.  
  548. The syntax of these objects is given in the form used in
  549. *Note References::, where "quoted" items should appear literally but
  550. without quotes, square bracketed ([ ]) items are optional, and | separates
  551. alternative choices.
  552.  
  553. * Menu:
  554.  
  555. * transform::    Transformation matrices.
  556. * camera::    Cameras.
  557. * window::    Windows.
  558.  
  559. 
  560. File: geomview  Node: transform, Prev: Non-geometric objects, Up: Non-geometric objects, Next: camera
  561.  
  562. Transform Objects
  563. -----------------
  564.  
  565. Where a single 4x4 matrix is expected -- as in the
  566. `INST' `transform' field, the camera's `camtoworld' transform
  567. and the Geomview `xform*' commands -- use a transform object.
  568.  
  569. Note that a transform is distinct from a `TLIST', which is a type
  570. of geometry.  `TLIST's can contain one or more 4x4 transformations;
  571. "transform" objects must have exactly one.
  572.  
  573. Why have both?  In many places -- e.g. camera positioning -- it's only
  574. meaningful to have a single transform.  Using a separate object type
  575. enforces this.
  576.  
  577. Syntax for a transform object is
  578.  
  579.      <transform> ::= 
  580.        [ "{" ]             (curly brace, generally needed to make
  581.                             the end of the object unambiguous.)
  582.  
  583.         [ "transform" ]    (optional keyword; unnecessary if the type
  584.                             is determined by the context, which it
  585.                             usually is.)
  586.         [ "define" <name> ]
  587.                            (defines a transform named <name>, setting
  588.                             its value from the stuff which follows)
  589.  
  590.            <sixteen floating-point numbers>
  591.                            (interpreted as a 4x4 homogeneous transform
  592.                     given row by row, intended to apply to a
  593.                             row vector multiplied on its LEFT, so that e.g.
  594.                             Euclidean translations appear in the bottom row)
  595.         | 
  596.            "<" <filename>  (meaning: read transform from that file)
  597.         |
  598.            ":" <name>      (meaning: use variable <name>,
  599.                              defined elsewhere; if undefined the initial
  600.                              value is the identity transform)
  601.  
  602.       [ "}" ]              (matching curly brace)
  603.  
  604. The whole should be enclosed in { braces }.  Braces are not essential
  605. if exactly one of the above items is present, so e.g. a 4x4 array of
  606. floats standing alone may but needn't have braces.
  607.  
  608. Some examples, in contexts where they might be used:
  609.  
  610.      # Example 1: A gcl command to define a transform
  611.      # called "fred"
  612.  
  613.      (read transform { transform  define fred
  614.               1 0 0 0
  615.               0 1 0 0
  616.               0 0 1 0
  617.              -3 0 1 1
  618.          }
  619.      )
  620.  
  621.      # Example 2:  A camera object using transform
  622.      # "fred" for camera positioning
  623.      # Given the definition above, this puts the camera at
  624.      # (-3, 0, 1), looking toward -Z.
  625.  
  626.      { camera
  627.              halfyfield 1
  628.              aspect 1.33
  629.              camtoworld { : fred }
  630.      }
  631.  
  632. 
  633. File: geomview  Node: camera, Prev: transform, Up: Non-geometric objects, Next: window
  634.  
  635. cameras
  636. -------
  637.  
  638. A camera object specifies the following properties of a camera:
  639.  
  640. position and orientation
  641.      specified by either a camera-to-world or world-to-camera transformation;
  642.      this transformation does not include the projection, so it's typically
  643.      just a combination of translation and rotation.  Specified as a
  644.      transform object, typically a 4x4 matrix.
  645. "focus" distance
  646.      Intended to suggest a typical distance from the camera to the object of
  647.      interest; used for default camera positioning (the camera is placed at
  648.      (X,Y,Z) = (0,0,focus) when reset) and for adjusting field-of-view when
  649.      switching between perspective and orthographic views.
  650. window aspect ratio
  651.      True aspect ratio in the sense <Xsize>/<Ysize>.  This normally should
  652.      agree with the aspect ratio of the camera's window.  Geomview normally
  653.      adjusts the aspect ratio of its cameras to match their associated
  654.      windows.
  655. near and far clipping plane distances
  656.      Note that both must be strictly greater than zero.  Very large
  657.      <far>/<near> distance ratios cause Z-buffering to behave badly; part of
  658.      an object may be visible even if somewhat more distant than another.
  659. field of view
  660.      Specified in either of two forms.
  661.             `fov '
  662.      
  663.           is the field of view -- in degrees if perspective, or linear
  664.           distance if orthographic -- in the *shorter* direction.
  665.             `halfyfield '
  666.      
  667.           is half the projected Y-axis field, in world coordinates (not angle!),
  668.           at unit distance from the camera.  For a perspective camera, halfyfield
  669.           is related to angular field:
  670.  
  671.                    halfyfield = tan( Y_axis_angular_field / 2 )
  672.  
  673.           while for an orthographic one it's simply:
  674.  
  675.                        halfyfield = Y_axis_linear_field / 2
  676.  
  677.  
  678.      This odd-seeming definition is (a) easy to calculate with and
  679.      (b) well-defined in both orthographic and perspective views.
  680.  
  681.  
  682. The syntax for a camera is:
  683.  
  684.      <camera> ::=
  685.  
  686.         [ "camera" ]            (optional keyword)
  687.          [ "{" ]            (opening brace, generally required)
  688.          [ "define" <name> ]
  689.  
  690.          "<" <filename>
  691.            |
  692.          ":" <name>
  693.            |
  694.                      (or any number of the following,
  695.                       in any order...)
  696.  
  697.          "perspective"  {"0" | "1"}        (default 1)
  698.                          (otherwise orthographic)
  699.  
  700.          "stereo"       {"0" | "1"}        (default 0)
  701.                          (otherwise mono)
  702.  
  703.          "worldtocam" <transform>    (see transform syntax above)
  704.  
  705.          "camtoworld" <transform>
  706.                      (no point in specifying both
  707.                       camtoworld and worldtocam; one is
  708.                       constrained to be the inverse of                         the other)
  709.  
  710.          "halfyfield" <half-linear-Y-field-at-unit-distance>
  711.                      (default tan 40/2 degrees)
  712.  
  713.          "fov"        (angular field-of-view if perspective,
  714.                   linear field-of-view otherwise.
  715.                   Measured in whichever direction is smaller,
  716.                   given the aspect ratio.  When aspect ratio
  717.                   changes -- e.g. when a window is reshaped --
  718.                   "fov" is preserved.)
  719.  
  720.          "frameaspect" <aspect-ratio>    (X/Y) (default 1.333)
  721.  
  722.          "near"  <near-clipping-distance>    (default 0.1)
  723.     
  724.          "far"    <far-clipping-distance>        (default 10.0)
  725.  
  726.          "focus" <focus-distance>        (default 3.0)
  727.  
  728.     
  729.           [ "}" ]                (matching closebrace)
  730.  
  731.  
  732. 
  733. File: geomview  Node: window, Prev: camera, Up: Non-geometric objects, Next: Customization
  734.  
  735. window
  736. ------
  737.  
  738. A window object specifies size, position, and other window-system
  739. related information about a window in a device-independent way.
  740.  
  741. The syntax for a window object is:
  742.  
  743.      window ::=
  744.  
  745.          [ "window" ]            (optional keyword)
  746.            [ "{" ]            (curly brace, often required)
  747.  
  748.                          (any of the following, in any order)
  749.  
  750.              "size"  <xsize> <ysize>
  751.                      (size of the window)
  752.  
  753.              "position"  <xmin> <xmax> <ymin> <ymax>
  754.                      (position & size)
  755.  
  756.  
  757.              "noborder"
  758.                      (specifies the window should
  759.                       have no window border)
  760.  
  761.              "pixelaspect"  <aspect>
  762.                      (specifies the true visual aspect ratio
  763.                       of a pixel in this window in the sense
  764.                       xsize/ysize, normally 1.0.
  765.                       For stereo hardware which stretches the
  766.                       display vertically by a factor of 2,
  767.                       "pixelaspect 0.5" might do.
  768.                       The value is used when computing the
  769.                       projection of a camera associated with
  770.                       this window.)
  771.  
  772.            [ "}" ]            (matching closebrace)
  773.  
  774. Window objects are used in the Geomview `window' and
  775. `ui-panel' commands to set default properties for future windows or
  776. to change those of an existing window.
  777.  
  778.  
  779. 
  780. File: geomview  Node: Customization, Prev: window, Up: Top, Next: Modules
  781.  
  782. Customization: `.geomview' files
  783. ********************************
  784.  
  785. When Geomview is started, it loads and executes commands in a
  786. system-wide startup file named `.geomview'.  This file is in the
  787. `data' subdirectory of the Geomview distribution directory
  788. `/u/gcg/ngrap/data' on the Geometry Center's computer system) and
  789. contains gcl commands to configure Geomview in a way
  790. common to all users on the system.
  791.  
  792. Next, Geomview looks for the file `~/.geomview' (`~'
  793. stands for your home directory).  You can use this to configure
  794. your own default Geomview behavior to suit your tastes.
  795.  
  796. After reading `~/.geomview', Geomview looks for a file named
  797. `.geomview' in the current directory.  If such a file exists
  798. Geomview reads it, unless it is the same as `~/.geomview' (which
  799. would be the case if you are running Geomview from your home directory).
  800. You can use the current directory's `.geomview' to create a Geomview
  801. customization specific to a certain project.
  802.  
  803. You can use `.geomview' files to control all kinds of things about
  804. Geomview.  They can contain any valid gcl statements.  Especially
  805. useful is the `ui-panel' command which controls the initial
  806. placement of Geomview's panels.  For an example see the system-wide
  807. `.geomview' file mentioned above.  For details of gcl,
  808. *Note GCL::.
  809.  
  810. It is a good idea to enclose all the commands you put in a
  811. `.geomview' file in a `progn' statement in order to cause
  812. Geomview to execute them all at once.  Otherwise Geomview might execute
  813. them sequentially over the first few refresh cycles after starting up.
  814.  
  815. 
  816. File: geomview  Node: Modules, Prev: Customization, Up: Top, Next: Interface
  817.  
  818. External Modules
  819. ****************
  820.  
  821. An external module is a program that interacts with Geomview.  A
  822. module communicates with Geomview through gcl and can
  823. control any apsect of Geomview that you can control through Geomview's
  824. user interface.
  825.  
  826. In many cases an external module is a specialized program that
  827. implements some mathematical algorithm that creates a geometric
  828. object that changes shape as the algorithm progresses.  The module
  829. informs Geomview of the new object shape at each step, so the object
  830. appears to evolve with time in the Geomview window.  In this way
  831. Geomview serves as a *display engine* for the module.
  832.  
  833. An external module may be interactive.  It can respond to mouse and
  834. keyboard events that take place in a Geomview window, thus extending
  835. the capability of Geomview itself.
  836.  
  837. * Menu:
  838.  
  839. * Interface::               How External Modules Interface with Geomview.
  840. * Example1::                Simple External Module.
  841. * Example2::                Simple External Module with FORMS Control Panel.
  842. * Forms::                   The FORMS Library.
  843. * Example3::                External Module with Bi-Directional Communication.
  844. * Example4::                Simple Tcl/Tk Module Demonstrating Picking.
  845. * Module Installation::     Module Installation.
  846.  
  847. 
  848. File: geomview  Node: Interface, Prev: Modules, Up: Modules, Next: Example1
  849.  
  850. How External Modules Interface with Geomview
  851. ============================================
  852.  
  853. External modules appear in the *Modules* browser in Geomview's
  854. *Main* panel.  To run a module, click the left mouse button on
  855. the module's entry in the browser.  While the module is running, an
  856. additional line for that module will appear in red in the browser.
  857. This line begins with a number in brackets, which indicates the
  858. *instace* number of the module.  (For some modules it makes sense
  859. to have more than one instance of the module running at the same
  860. time.)  You can kill an external module by clicking on its red
  861. instance entry.
  862.  
  863. By default when Geomview starts, it displays all the modules that have
  864. been installed on your system. 
  865.  
  866. For instructions on installing a module on your system so that it will
  867. appear in the *Modules* browser every time Geomview is run by
  868. anyone on your system, *Note Module Installation::.
  869.  
  870. When Geomview invokes an external module, it creates pipes connected
  871. to the module's standard input and output. (Pipes are like files
  872. except they are used for communication between programs rather than
  873. for storing things on a disk.)  Geomview interprets anything that the
  874. module writes to its standard output as a gcl command.
  875. Likewise, if the exernal module requests any data from Geomview,
  876. Geomview writes that data to the module's standard input.  Thus all a
  877. module has to do in order to communicate with Geomview is write
  878. commands to standard output and (optionally) receive data on standard
  879. input.  Note that this means that the module cannot use standard input
  880. and output for communicating with the user.  If a module needs to
  881. communicate with the user it can do so either through a control
  882. panel of its own or else by responding to certain events that it finds
  883. out about from Geomview.
  884.  
  885. 
  886. File: geomview  Node: Example1, Prev: Interface, Up: Modules, Next: Example2
  887.  
  888. Example 1: Simple External Module
  889. =================================
  890.  
  891. This section gives a very simple external module which displays an
  892. oscillating mesh.  To try out this example, make a copy of the file
  893. `example1.c' (it is distributed with Geomview in the `doc'
  894. subdirectory) in your directory and compile it with the command
  895.  
  896.      cc -o example1 example1.c -lm
  897.  
  898. Then put the line
  899.  
  900.      (emodule-define "Example 1" "./example1")
  901.  
  902. in a file called `.geomview' in your current directory.  Then invoke
  903. Geomview; it is important that you compile the example program, create
  904. the `.geomview' file, and invoke Geomview all in the same
  905. directory.  You should see "Example 1" in the *Modules* browser
  906. of Geomview's *Main* panel; click on this entry in the browser to
  907. start the module.  A surface should appear in your camera window and should
  908. begin oscillating.  You can stop the module by clicking on the red "[1]
  909. Example 1" line in the *Modules* browser.
  910.  
  911.      /*
  912.       * example1.c: oscillating mesh
  913.       *
  914.       * This example module is distributed with the Geomview manual.
  915.       * If you are not reading this in the manual, see the "External
  916.       * Modules" chapter of the manual for more details.
  917.       *
  918.       * This module creates an oscillating mesh.
  919.       */
  920.  
  921.      #include <math.h>
  922.      #include <stdio.h>
  923.  
  924.      /* F is the function that we plot
  925.       */
  926.      float F(x,y,t)
  927.           float x,y,t;
  928.      {
  929.        float r = sqrt(x*x+y*y);
  930.        return(sin(r + t)*sqrt(r));
  931.      }
  932.  
  933.      main(argc, argv)        
  934.           char **argv;
  935.      {
  936.        int xdim, ydim;
  937.        float xmin, xmax, ymin, ymax, dx, dy, t, dt;
  938.  
  939.        xmin = ymin = -5;             /* Set x and y            */
  940.        xmax = ymax = 5;              /*    plot ranges         */
  941.        xdim = ydim = 24;             /* Set x and y resolution */
  942.        dt = 0.1;                     /* Time increment is 0.1  */
  943.  
  944.        /* Geomview setup.  We begin by sending the command
  945.         *            (geometry example { : foo})
  946.         * to Geomview.  This tells Geomview to create a geom called
  947.         * "example" which is an instance of the handle "foo".
  948.         */
  949.        printf("(geometry example { : foo })\n");
  950.        fflush(stdout);
  951.  
  952.        /* Loop until killed.
  953.         */
  954.        for (t=0; ; t+=dt) {
  955.          UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
  956.        }
  957.      }
  958.  
  959.      /* UpdateMesh sends one mesh iteration to Geomview.  This consists of
  960.       * a command of the form
  961.       *    (read geometry { define foo
  962.       *       MESH
  963.       *       ...
  964.       *    })
  965.       * where ... is the actual data of the mesh.  This command tells
  966.       * Geomview to make the value of the handle "foo" be the specified
  967.       * mesh.
  968.       */
  969.      UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
  970.           float xmin, xmax, ymin, ymax, t;
  971.           int xdim, ydim;
  972.      {
  973.        int i,j;
  974.        float x,y, dx,dy;
  975.  
  976.        dx = (xmax-xmin)/(xdim-1);
  977.        dy = (ymax-ymin)/(ydim-1);
  978.  
  979.        printf("(read geometry { define foo \n");
  980.        printf("MESH\n");
  981.        printf("%1d %1d\n", xdim, ydim);
  982.        for (j=0, y = ymin; j<ydim; ++j, y += dy) {
  983.          for (i=0, x = xmin; i<xdim; ++i, x += dx) {
  984.            printf("%f %f %f\t", x, y, F(x,y,t));
  985.          }
  986.          printf("\n");
  987.        }
  988.        printf("})\n");
  989.        fflush(stdout);
  990.      }
  991.  
  992. The module begins by defining a function `F(x,y,t)' that
  993. specifies a time-varying surface.  The purpose of the module is to
  994. animate this surface over time.
  995.  
  996. The main program begins by defining some variables that specify
  997. the parameters with which the function is to be plotted.
  998.  
  999. The next bit of code in the main program prints the following
  1000. line to standard output
  1001.  
  1002.      (geometry example { : foo })
  1003.  
  1004. This tells Geomview to create a geom called `example' which is an
  1005. instance of the handle `foo'.  *Handles* are a part of the
  1006. OOGL file format which allow you to name a piece of geometry whose value
  1007. can be specified elsewhere (and in this case updated many times); for
  1008. more information on handles, *Note OOGL File Formats:: In this case,
  1009. `example' is the title by which the user will see the object in
  1010. Geomview's object browser, and `foo' is the internal name of the
  1011. handle that the object is a reference to.
  1012.  
  1013. We then do `fflush(stdout)' to ensure that Geomview
  1014. receives this command immediately.  In general, since pipes may be
  1015. buffered, an external module should do this whenever it wants to be
  1016. sure Geomview has actually received everything it has printed out.
  1017.  
  1018. The last thing in the main program is an infinite loop that cycles
  1019. through calls to the procedure `UpdateMesh' with increasing
  1020. values of `t'.  `UpdateMesh' sends Geomview a command
  1021. of the form
  1022.  
  1023.      (read geometry { define foo 
  1024.      MESH
  1025.      24 24
  1026.      ...
  1027.      })
  1028.  
  1029. where `...' is a long list of numbers.  This command tells Geomview
  1030. to make the value of the handle `foo' be the specified mesh.  As
  1031. soon as Geomview receives this command, the geom being displayed
  1032. changes to reflect the new geometry.
  1033.  
  1034. The mesh is given in the format of an OOGL MESH.  This begins with
  1035. the keyword `MESH'.  Next come two numbers that give the x and y
  1036. dimensions of the mesh; in this case they are both 24.  This line is
  1037. followed by 24 lines, each containing 24 triples of numbers.  Each of
  1038. these triples is a point on the surface.  Then finally there is a line
  1039. with "`})'" on it that ends the "`{'" which began the
  1040. `define' statement and the "`('" that began the command.  For
  1041. more details on the format of MESH data, *Note MESH::.
  1042.  
  1043. This module could be written without the use of handles by having it
  1044. write out commands of the form
  1045.  
  1046.      (geometry example {
  1047.      MESH
  1048.      24 24
  1049.      ...
  1050.      })
  1051.  
  1052. This first time Geomview receives a command of this form it would create
  1053. a geom called `example' with the given `MESH' data.
  1054. Subsequent `(geometry example ...)' commands would cause
  1055. Geomview to replace the geometry of the geom `example' with the new
  1056. `MESH' data.  If done in this way there would be no need to send
  1057. the initial `(geometry example { : foo })' command as above.  The
  1058. handle technique is useful, however, because it can be used in more
  1059. general situations where a handle represents only part of a complex
  1060. geom, allowing an external module to replace only that part without
  1061. having to retransmit the entire geom.  For more information on handles,
  1062. *Note GCL::.
  1063.  
  1064. The module loops through calls to `UpdateMesh' which print out
  1065. commands of the above form one after the other as fast as possible.
  1066. The loop continues indefinitely; the module will terminate when the
  1067. user kills it by clicking on its instance line in the *Modules*
  1068. browser, or else when Geomview exits.
  1069.  
  1070. Sometimes when you terminate this module by clicking on its instance
  1071. entry the *Modules* browser, Geomview will kill it while it is in
  1072. the middle of sending a command to Geomview.  Geomview will then receive
  1073. only a piece of a command and will print out a cryptic but harmless
  1074. error message about this.  When a module has a user interface panel
  1075. it can use a "Quit" button to provide a more graceful way for the user
  1076. to terminate the module.  See the next example.
  1077.  
  1078. You can run this module in a shell window without Geomview to see the
  1079. commands it prints out.  You will have to kill it with
  1080. `ctrl-C' to get it to stop.
  1081.  
  1082. 
  1083. File: geomview  Node: Example2, Prev: Example1, Up: Modules, Next: Forms
  1084.  
  1085. Example 2: Simple External Module with FORMS Control Panel
  1086. ==========================================================
  1087.  
  1088. This section gives a new version of the above module --- one that
  1089. includes a user interface panel for controlling the velocity of the
  1090. oscillation.  We use the FORMS library by Mark Overmars for the control
  1091. panel.  The FORMS library is a public domain user interface toolkit for
  1092. IRISes; for more information *Note Forms::.
  1093.  
  1094. To try out this example, make a copy of the file
  1095. `example2.c' (distributed with Geomview in the `doc'
  1096. subdirectory) in your directory and compile it with the command
  1097.  
  1098.      cc -I/u/gcg/ngrap/include -o example2 example2.c \
  1099.        -L/u/gcg/ngrap/lib/sgi -lforms -lfm_s -lgl_s -lm
  1100.  
  1101. If you are not using the Geometry Center's computer system you should
  1102. replace the string `/u/gcg/ngrap' above with the pathname of the
  1103. Geomview distribution directory on your system.  (The forms library is
  1104. distributed with Geomview and the `-I' and `-L' options above
  1105. tell the compiler where to find it.)
  1106.  
  1107. Then put the line
  1108.  
  1109.      (emodule-define "Example 2" "./example2")
  1110.  
  1111. in a file called `.geomview' in the current directory and invoke
  1112. Geomview from that directory.  Click on the "Example 2" entry in the
  1113. *Modules* browser to invoke the module.  A small control panel
  1114. should appear.  You can then control the velocity of the mesh
  1115. oscillation by moving the slider.
  1116.  
  1117.      /*
  1118.       * example2.c: oscillating mesh with FORMS control panel
  1119.       *
  1120.       * This example module is distributed with the Geomview manual.
  1121.       * If you are not reading this in the manual, see the "External
  1122.       * Modules" chapter of the manual for an explanation.
  1123.       *
  1124.       * This module creates an oscillating mesh and has a FORMS control
  1125.       * panel that lets you change the speed of the oscillation with a
  1126.       * slider.
  1127.       */
  1128.  
  1129.      #include <math.h>
  1130.      #include <stdio.h>
  1131.      #include <sys/time.h>           /* for struct timeval below */
  1132.  
  1133.      #include "forms.h"              /* for FORMS library */
  1134.  
  1135.      FL_FORM *OurForm;
  1136.      FL_OBJECT *VelocitySlider;
  1137.      float dt;
  1138.  
  1139.      /* F is the function that we plot
  1140.       */
  1141.      float F(x,y,t)
  1142.           float x,y,t;
  1143.      {
  1144.        float r = sqrt(x*x+y*y);
  1145.        return(sin(r + t)*sqrt(r));
  1146.      }
  1147.  
  1148.      /* SetVelocity is the slider callback procedure; FORMS calls this
  1149.       * when the user moves the slider bar.
  1150.       */
  1151.      void SetVelocity(FL_OBJECT *obj, long val)
  1152.      {
  1153.        dt = fl_get_slider_value(VelocitySlider);
  1154.      }
  1155.  
  1156.      /* Quit is the "Quit" button callback procedure; FORMS calls this
  1157.       * when the user clicks the "Quit" button.
  1158.       */
  1159.      void Quit(FL_OBJECT *obj, long val)
  1160.      {
  1161.        exit(0);
  1162.      }
  1163.  
  1164.      /* create_form_OurForm() creates the FORMS panel by calling a bunch of
  1165.       * procedures in the FORMS library.  This code was generated
  1166.       * automatically by the FORMS designer program; normally this code
  1167.       * would be in a separate file which you would not edit by hand.  For
  1168.       * simplicity of this example, however, we include this code here.
  1169.       */
  1170.      create_form_OurForm()
  1171.      {
  1172.        FL_OBJECT *obj;
  1173.        FL_FORM *form;
  1174.        OurForm = form = fl_bgn_form(FL_NO_BOX,380.0,120.0);
  1175.        obj = fl_add_box(FL_UP_BOX,0.0,0.0,380.0,120.0,"");
  1176.        VelocitySlider = obj = fl_add_valslider(FL_HOR_SLIDER,20.0,30.0,
  1177.                                                340.0,40.0,"Velocity");
  1178.          fl_set_object_lsize(obj,FL_LARGE_FONT);
  1179.          fl_set_object_align(obj,FL_ALIGN_TOP);
  1180.          fl_set_call_back(obj,SetVelocity,0);
  1181.        obj = fl_add_button(FL_NORMAL_BUTTON,290.0,75.0,70.0,35.0,"Quit");
  1182.          fl_set_object_lsize(obj,FL_LARGE_FONT);
  1183.          fl_set_call_back(obj,Quit,0);
  1184.        fl_end_form();
  1185.      }
  1186.  
  1187.      main(argc, argv)        
  1188.           char **argv;
  1189.      {
  1190.        int xdim, ydim;
  1191.        float xmin, xmax, ymin, ymax, dx, dy, t;
  1192.        int fdmask;
  1193.        static struct timeval timeout = {0, 200000};
  1194.  
  1195.        xmin = ymin = -5;             /* Set x and y            */
  1196.        xmax = ymax = 5;              /*    plot ranges         */
  1197.        xdim = ydim = 24;             /* Set x and y resolution */
  1198.        dt = 0.1;                     /* Time increment is 0.1  */
  1199.  
  1200.        /* Forms panel setup.
  1201.         */
  1202.        foreground();
  1203.        create_form_OurForm();
  1204.        fl_set_slider_bounds(VelocitySlider, 0.0, 1.0);
  1205.        fl_set_slider_value(VelocitySlider, dt);
  1206.        fl_show_form(OurForm, FL_PLACE_SIZE, TRUE, "Example 2");
  1207.  
  1208.  
  1209.        /* Geomview setup.
  1210.         */
  1211.        printf("(geometry example { : foo })\n");
  1212.        fflush(stdout);
  1213.  
  1214.        /* Loop until killed.
  1215.         */
  1216.        for (t=0; ; t+=dt) {
  1217.          fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
  1218.          select(qgetfd()+1, &fdmask, NULL, NULL, &timeout);
  1219.          fl_check_forms();
  1220.          UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t);
  1221.        }
  1222.      }
  1223.  
  1224.      /* UpdateMesh sends one mesh iteration to Geomview
  1225.       */
  1226.      UpdateMesh(xmin, xmax, ymin, ymax, xdim, ydim, t)
  1227.           float xmin, xmax, ymin, ymax, t;
  1228.           int xdim, ydim;
  1229.      {
  1230.        int i,j;
  1231.        float x,y, dx,dy;
  1232.  
  1233.        dx = (xmax-xmin)/(xdim-1);
  1234.        dy = (ymax-ymin)/(ydim-1);
  1235.  
  1236.        printf("(read geometry { define foo \n");
  1237.        printf("MESH\n");
  1238.        printf("%1d %1d\n", xdim, ydim);
  1239.        for (j=0, y = ymin; j<ydim; ++j, y += dy) {
  1240.          for (i=0, x = xmin; i<xdim; ++i, x += dx) {
  1241.            printf("%f %f %f\t", x, y, F(x,y,t));
  1242.          }
  1243.          printf("\n");
  1244.        }
  1245.        printf("})\n");
  1246.        fflush(stdout);
  1247.      }
  1248.  
  1249. The code begins by including some header files needed for the event loop
  1250. and the FORMS library.  It then declares global variables for holding a
  1251. pointer to the slider FORMS object and the velocity `dt'.  These
  1252. are global because they are needed in the slider callback procedure
  1253. `SetVelocity', which forms calls every time the user moves the
  1254. slider bar. `SetVelocity' sets `dt' to be the new value of the
  1255. slider.
  1256.  
  1257. `Quit' is the callback procedure for the *Quit* button;
  1258. it provides a graceful way for the user to terminate the program.
  1259.  
  1260. The procedure `create_panel' calls a bunch of FORMS library
  1261. procedures to set up the control panel with slider and button.  For more
  1262. information on using FORMS to create interface panels see the FORMS
  1263. documentation.  In particular, FORMS comes with a graphical panel
  1264. designer that lets you design your panels interactively and generates
  1265. code like that in `create_panel'.
  1266.  
  1267. This example's main program is similar to the previous example, but
  1268. includes extra code to deal with setting up and managing the FORMS
  1269. panel.  
  1270.  
  1271. To set up the panel we call the GL procedure `foreground' to cause
  1272. the process to run in the foreground.  By default GL programs run in the
  1273. background, and for various reasons external modules that use FORMS
  1274. (which is based on GL) need to run in the foreground.  We then call
  1275. `create_panel' to create the panel and `fl_set_slider_value'
  1276. to set the initial value of the slider.  The call to `fl_show_form'
  1277. causes the panel to appear on the screen.
  1278.  
  1279. The first three lines of the main loop, starting with 
  1280.      fdmask = (1 << fileno(stdin)) | (1 << qgetfd());
  1281. check for and deal with events in the panel.  The call to `select'
  1282. imposes a delay on each pass through the main loop.  This call returns
  1283. either after a delay of 1/5 second or when the next GL event occurs, or
  1284. when data appears on standard input, whichever comes first.  The
  1285. `timeout' variable specifies the amount of time to wait on this
  1286. call; the first member (0 in this example) gives the number of seconds,
  1287. and the second member (200000 in this example) gives the number of
  1288. microseconds.  Finally, `fl_check_forms()' checks for and processes
  1289. any FORMS events that have happened; in this case this means calling
  1290. `SetVelocity' if the user has moved the slider or calling
  1291. `Quit' if the user has clicked on the *Quit* button.
  1292.  
  1293. The purpose of the delay in the loop is to keep the program from using
  1294. excessive amounts of CPU time running around its main loop when there
  1295. are no events to be processed.  This is not so crucial in this example,
  1296. and in fact may actually slow down the animation somewhat, but in
  1297. general with external modules that have event loops it is important to
  1298. do something like this because otherwise the module will needlessly take
  1299. CPU cycles away from other running programs (such as Geomview!)  even
  1300. when it isn't doing anything.
  1301.  
  1302. The last line of the main loop in this example, the call to
  1303. `UpdateMesh', is the same as in the previous example.
  1304.  
  1305. 
  1306. File: geomview  Node: Forms, Prev: Example2, Up: Modules, Next: Example3
  1307.  
  1308. The FORMS Library
  1309. =================
  1310.  
  1311. Geomview itself is written using Mark Overmar's public domain FORMS
  1312. library.  FORMS is a handy and relatively simple user interface toolkit
  1313. for IRISes.  Many Geomview external modules, including the examples in
  1314. this manual, use FORMS to create and manage control panels.
  1315.  
  1316. We distribute a version of the FORMS library with Geomview because it is
  1317. necessary in order to compile Geomview and many of our modules.  If you
  1318. use FORMS to write Geomview modules (or anything else, for that matter)
  1319. you may use this copy.  The header file `forms.h' is in the
  1320. `include' subdirectory, and the library file `libforms.a' is
  1321. in the `lib/sgi' subdirectory (these are subdirectories of the
  1322. Geomview distribution directory, `/u/gcg/ngrap' on the Geometry
  1323. Center's system).  In particular, you can link the example modules in
  1324. this manual using this copy.
  1325.  
  1326. FORMS is available via ftp on the Internet from a variety of sites,
  1327. including `cs.ruu.nl' or `glaurung.physics.mcgill.ca'.  It
  1328. comes with source code and extensive documentation.
  1329.  
  1330. If you wish you may use any other interface toolkit instead of FORMS in
  1331. an external module.  We chose FORMS because it is free and relatively
  1332. simple.
  1333.  
  1334.  
  1335. 
  1336. File: geomview  Node: Example3, Prev: Forms, Up: Modules, Next: Example4
  1337.  
  1338. Example 3: External Module with Bi-Directional Communication
  1339. ============================================================
  1340.  
  1341. The previous two example modules simply send commands to Geomview and do
  1342. not receive anything from Geomview.  This section describes a module
  1343. that communicates in both directions.  There are two types of
  1344. communication that can go from Geomview to an external module.  This
  1345. example shows *asynchronous* communication --- the module needs to
  1346. be able to respond at any moment to expressions that Geomview may emit
  1347. which inform the module of some change of state within Geomview.
  1348.  
  1349. (The other type of communication is *synchronous*, where a module
  1350. sends a request to Geomview for some piece of information and waits for
  1351. a response to come back before doing anything else.  The main gcl
  1352. command for requesting information of this type is `write'.  This
  1353. module does not do any synchronous communication.)
  1354.  
  1355. In ansynchronous communication, Geomview sends expressions that are
  1356. essentially echoes of gcl commands.  The external module sends
  1357. Geomview a command expressing interest in a certain command, and then
  1358. every time Geomview executes that command, the module receives a copy of
  1359. it.  This happens regardless of who sent the command to Geomview; it can
  1360. be the result of the user doing something with a Geomview panel, or
  1361. it may have come from another module or from a file that Geomview reads.
  1362. This is how a module can find out about and act on things that happen in
  1363. Geomview.
  1364.  
  1365. This example uses the OOGL lisp library to parse and act on the
  1366. expressions that Geomview writes to the module's standard input.  This
  1367. library is actually part of Geomview itself --- we wrote the library in
  1368. the process of implementing gcl.  It is also convenient to use it in
  1369. external modules that must understand a of subset of gcl ---
  1370. specifically, those commands that the module has expressed interest in.
  1371.  
  1372. This example shows how a module can receive user pick events, i.e.
  1373. when the user clicks the right mouse button with the cursor over a geom
  1374. in a Geomview camera window.  When this happens Geomview generates an
  1375. internal call to a procedure called `pick'; the arguments to the
  1376. procedure give information about the pick, such as what object was
  1377. picked, the coordinates of the picked point, etc.  If an external module
  1378. has expressed interest in calls to `pick', then whenever
  1379. `pick' is called Geomview will echo the call to the module's
  1380. standard input.  The module can then do whatever it wants with the pick
  1381. information.
  1382.  
  1383. This module is the same as the *Nose* module that comes with
  1384. Geomview.  Its purpose is to illustrate picking.  Whenever you pick on a
  1385. geom by clicking the right mouse button on it, the module draws a little
  1386. box at the spot where you clicked.  Usually the box is yellow.  If you
  1387. pick a vertex, the box is colored magenta.  If you pick a point on an
  1388. edge of an object, the module will also highlight the edge by drawing
  1389. cyan boxes at its endpoints and drawing a yellow line along the edge.
  1390.  
  1391. Note that in order for this module to actually do anything you must have
  1392. a geom loaded into Geomview and you must click the right mouse button
  1393. with the cursor over a part of the geom.
  1394.  
  1395.      /*
  1396.       * example3.c: external module with bi-directional communication
  1397.       *
  1398.       * This example module is distributed with the Geomview manual.
  1399.       * If you are not reading this in the manual, see the "External
  1400.       * Modules" chapter of the manual for an explanation.
  1401.       *
  1402.       * This module is the same as the "Nose" program that is distributed
  1403.       * with Geomview.  It illustrates how a module can find out about
  1404.       * and respond to user pick events in Geomview.  It draws a little box
  1405.       * at the point where a pick occurrs.  The box is yellow if it is not
  1406.       * at a vertex, and magenta if it is on a vertex.  If it is on an edge,
  1407.       * the program also marks the edge.
  1408.       *
  1409.       * To compile:
  1410.       *
  1411.       *   cc -I/u/gcg/ngrap/include -g -o example3 example3.c \
  1412.       *      -L/u/gcg/ngrap/lib/sgi -loogl -lm
  1413.       *
  1414.       * If you are not on the Geometry Center's system you should replace
  1415.       * "/u/gcg/ngrap" above with the pathname of the Geomview distribution
  1416.       * directory on your system.
  1417.       */
  1418.  
  1419.      #include <stdio.h>
  1420.      #include "lisp.h"               /* We use the OOGL lisp library */
  1421.      #include "pickfunc.h"           /* for PICKFUNC below */
  1422.      #include "3d.h"                 /* for 3d geometry library */
  1423.  
  1424.      /* boxstring gives the OOGL data to define the little box that
  1425.       * we draw at the pick point.  NOTE:  It is very important to
  1426.       * have a newline at the end of the OFF object in this string.
  1427.       */
  1428.      char boxstring[] = "\
  1429.      INST\n\
  1430.      transform\n\
  1431.      .04 0 0 0\n\
  1432.      0 .04 0 0\n\
  1433.      0 0 .04 0\n\
  1434.      0 0 0 1\n\
  1435.      geom\n\
  1436.      OFF\n\
  1437.      8 6 12\n\
  1438.      \n\
  1439.      -.5 -.5 -.5     # 0   \n\
  1440.      .5 -.5 -.5      # 1   \n\
  1441.      .5  .5 -.5      # 2   \n\
  1442.      -.5  .5 -.5     # 3   \n\
  1443.      -.5 -.5  .5     # 4   \n\
  1444.      .5 -.5  .5      # 5   \n\
  1445.      .5  .5  .5      # 6   \n\
  1446.      -.5  .5  .5     # 7   \n\
  1447.      \n\
  1448.      4 0 1 2 3\n\
  1449.      4 4 5 6 7\n\
  1450.      4 2 3 7 6\n\
  1451.      4 0 1 5 4\n\
  1452.      4 0 4 7 3\n\
  1453.      4 1 2 6 5\n";
  1454.  
  1455.      progn()
  1456.      {
  1457.        printf("(progn\n");
  1458.      }
  1459.  
  1460.      endprogn()
  1461.      {
  1462.        printf(")\n");
  1463.        fflush(stdout);
  1464.      }
  1465.  
  1466.      Initialize()
  1467.      {
  1468.        extern LObject *Lpick();  /* This is defined by PICKFUNC below but must */
  1469.                        /* be used in the following LDefun() call */
  1470.        LInit();
  1471.        LDefun("pick", Lpick, NULL);
  1472.  
  1473.        progn(); {
  1474.          /* Define handle "littlebox" for use later
  1475.           */
  1476.          printf("(read geometry { define littlebox { %s }})\n", boxstring);
  1477.  
  1478.          /* Express interest in pick events; see Geomview manual for explanation.
  1479.           */
  1480.          printf("(interest (pick world * * * * nil nil nil nil nil))\n");
  1481.  
  1482.          /* Define "pick" object, initially the empty list (= null object).
  1483.           * We replace this later upon receiving a pick event.
  1484.           */
  1485.          printf("(geometry \"pick\" { LIST } )\n");
  1486.  
  1487.          /* Make the "pick" object be non-pickable.
  1488.           */
  1489.          printf("(pickable \"pick\" no)\n");
  1490.  
  1491.          /* Turn off normalization, so that our pick object will appear in the
  1492.           * right place.
  1493.           */
  1494.          printf("(normalization \"pick\" none)\n");
  1495.  
  1496.          /* Don't draw the pick object's bounding box.
  1497.           */
  1498.          printf("(bbox-draw \"pick\" off)\n");
  1499.  
  1500.        } endprogn();
  1501.      }
  1502.  
  1503.      /* The following is a macro call that defines a procedure called
  1504.       * Lpick().  The reason for doing this in a macro is that that macro
  1505.       * encapsulates a lot of necessary stuff that would be the same for
  1506.       * this procedure in any program.  If you write a Geomview module that
  1507.       * wants to know about user pick events you can just copy this macro
  1508.       * call and change the body to suit your needs; the body is the last
  1509.       * argument to the macro and is delimited by curly braces.
  1510.       *
  1511.       * The first argument to the macro is the name of the procedure to
  1512.       * be defined, "Lpick".
  1513.       *
  1514.       * The next two arguments are numbers which specify the sizes that
  1515.       * certain arrays inside the body of the procedure should have.
  1516.       * These arrays are used for storing the face and path information
  1517.       * of the picked object.  In this module we don't care about this
  1518.       * information so we declare them to have length 1, the minimum
  1519.       * allowed.
  1520.       *
  1521.       * The last argument is a block of code to be executed when the module
  1522.       * receives a pick event.  In this body you can refer to certain local
  1523.       * variables that hold information about the pick.  For details see
  1524.       * Example 3 in the Extenal Modules chapter of the Geomview manual.
  1525.       */
  1526.      PICKFUNC(Lpick, 1, 1,
  1527.      {           
  1528.        handle_pick(pn>0, &point, vn>0, &vertex, en>0, edge);
  1529.      })
  1530.  
  1531.      handle_pick(picked, p, vert, v, edge, e)
  1532.           int picked;                /* was something actually picked?     */
  1533.           int vert;                  /* was the pick near a vertex?        */
  1534.           int edge;                  /* was the pick near an edge?         */
  1535.           HPoint3 *p;                /* coords of pick point               */
  1536.           HPoint3 *v;                /* coords of picked vertex            */
  1537.           HPoint3 e[2];              /* coords of endpoints of picked edge */
  1538.      {
  1539.        Normalize(&e[0]);             /* Normalize makes 4th coord 1.0 */
  1540.        Normalize(&e[1]);
  1541.        Normalize(p);
  1542.        progn(); {
  1543.          if (!picked) {
  1544.            printf("(geometry \"pick\" { LIST } )\n");
  1545.          } else {
  1546.            /*
  1547.             * Put the box in place, and color it magenta if it's on a vertex,
  1548.             * yellow if not.
  1549.             */
  1550.            printf("(xform-set pick { 1 0 0 0  0 1 0 0  0 0 1 0  %g %g %g 1 })\n",
  1551.                   p->x, p->y, p->z);
  1552.            printf("(geometry \"pick\"\n");
  1553.            if (vert) printf("{ appearance { material { diffuse 1 0 1 } }\n");
  1554.            else printf("{ appearance { material { diffuse 1 1 0 } }\n");
  1555.            printf("  { LIST { :littlebox }\n");
  1556.       
  1557.            /*
  1558.             * If it's on an edge and not a vertex, mark the edge
  1559.             * with cyan boxes at the endpoins and a black line
  1560.             * along the edge.
  1561.             */
  1562.            if (edge && !vert) {
  1563.              e[0].x -= p->x; e[0].y -= p->y; e[0].z -= p->z;
  1564.              e[1].x -= p->x; e[1].y -= p->y; e[1].z -= p->z;
  1565.              printf("{ appearance { material { diffuse 0 1 1 } }\n\
  1566.        LIST\n\
  1567.         { INST transform 1 0 0 0 0 1 0 0 0 0 1 0 %f %f %f 1 geom :littlebox }\n\
  1568.         { INST transform 1 0 0 0 0 1 0 0 0 0 1 0 %f %f %f 1 geom :littlebox }\n\
  1569.         { VECT\n\
  1570.                1 2 1\n\
  1571.                2\n\
  1572.                1\n\
  1573.                %f %f %f\n\
  1574.                %f %f %f\n\
  1575.                1 1 0 1\n\
  1576.         }\n\
  1577.        }\n",
  1578.                     e[0].x, e[0].y, e[0].z,
  1579.                     e[1].x, e[1].y, e[1].z,
  1580.                     e[0].x, e[0].y, e[0].z,
  1581.                     e[1].x, e[1].y, e[1].z);
  1582.            }
  1583.            printf("    }\n  }\n)\n");
  1584.          }
  1585.  
  1586.        } endprogn();
  1587.  
  1588.      }
  1589.  
  1590.      Normalize(HPoint3 *p)
  1591.      {
  1592.        if (p->w != 0) {
  1593.          p->x /= p->w;
  1594.          p->y /= p->w;
  1595.          p->z /= p->w;
  1596.          p->w = 1;
  1597.        }
  1598.      }
  1599.  
  1600.      main()
  1601.      {
  1602.        Lake *lake;
  1603.        LObject *lit, *val;
  1604.        extern char *getenv();
  1605.  
  1606.        Initialize();
  1607.  
  1608.        lake = LakeDefine(stdin, stdout, NULL);
  1609.        while (!feof(stdin)) {
  1610.  
  1611.          /* Parse next lisp expression from stdin.
  1612.           */
  1613.          lit = LSexpr(lake);
  1614.  
  1615.          /* Evaluate that expression; this is where Lpick() gets called.
  1616.           */
  1617.          val = LEval(lit);
  1618.  
  1619.          /* Free the two expressions from above.
  1620.           */
  1621.          LFree(lit);
  1622.          LFree(val);
  1623.        }
  1624.      }
  1625.  
  1626. The code begins by defining procedures `progn()' and
  1627. `endprogn()' which begin and end a Geomview `progn' group.
  1628. The purpose of the Geomview `progn' command is to group commands
  1629. together and cause Geomview to execute them all at once, without
  1630. refreshing any graphics windows until the end.  It is a good idea to
  1631. group blocks of commands that a module sends to Geomview like this so
  1632. that the user sees their cumulative effect all at once.
  1633.  
  1634. Procedure `Initialize()' does various things needed at program
  1635. startup time.  It initializes the lisp library by calling
  1636. `LInit()'.  Any program that uses the lisp library should call this
  1637. once before calling any other lisp library functions.  It then calls
  1638. `LDefun' to tell the library about our `pick' procedure, which
  1639. is defined further down with a call to the `DEFPICKFUNC' macro.
  1640. Then it sends a bunch of setup commands to Geomview, grouped in a
  1641. `progn' block.  This includes defining a handle called `littlebox'
  1642. that stores the geometry of the little box.  Next it sends the command
  1643.  
  1644.      (interest (pick world * * * * nil nil nil nil nil))
  1645.  
  1646. which tells Geomview to notify us when a pick event happens.
  1647.  
  1648. The syntax of this `interest' statement merits some explanation.
  1649. In general `interest' takes one argument which is a (parenthesized)
  1650. expression representing a Geomview function call.  It specifies a type
  1651. of call that the module is interested in knowing about.  The arguments
  1652. can be any particular argument values, or the special symbols `*'
  1653. or `nil'.  For example, the first argument in the `pick'
  1654. expression above is `world'.  This means that the module is
  1655. interested in calls to `pick' where the first argument, which
  1656. specifies the coordinate system, is `world'.  A `*' is like a
  1657. wild-card; it means that the module is interested in calls where the
  1658. corresponding argument has any value.  The word `nil' is like
  1659. `*', except that the argument's value is not reported to the
  1660. module.  This is useful for cutting down on the amount of data that must
  1661. be transmitted in cases where there are arguments that the module
  1662. doesn't care about.
  1663.  
  1664. The second, third, fourth, and fifth arguments to the `pick'
  1665. command give the name, pick point coordinates, vertex coordinates, and
  1666. edge coordinates of a pick event.  We specify these by `*''s above.
  1667. The remaining five arguments to the `pick' command give other
  1668. information about the pick event that we do not care about in this
  1669. module, so we specify these with `nil''s.  For the details of the
  1670. arguments to `pick', *Note GCL::.
  1671.  
  1672. The `geometry' statement defines a geom called `pick' that is
  1673. initially an empty list, specified as ` { LIST } '; this is the
  1674. best way of specifying a null geom.  The module will replace this with
  1675. something useful by sending Geomview another `geometry' command
  1676. when the user picks something.  Next we arrange for the `pick'
  1677. object to be non-pickable, and turn normalization off for it so that
  1678. Geomview will display it in the size and location where we put it,
  1679. rather than resizing and relocating it to fit into the unit cube.
  1680.  
  1681. The next function in the file, `Lpick', is defined with a strange
  1682. looking call to a macro called `PICKFUNC', defined in the header
  1683. file `pickfunc.h'.  This is the function for handling pick events.
  1684. The reason we provide a macro for this is that that macro encapsulates a
  1685. lot of necessary stuff that would be the same for the pick-handling
  1686. function in any program.  If you write a Geomview module that wants to
  1687. know about user pick events you can just copy this macro call and change
  1688. it to suit yours needs.
  1689.  
  1690. In general the syntax for `PICKFUNC' is
  1691.      PICKFUNC(NAME, MAXFACEVERTS, MAXPATHLEN, BLOCK)
  1692. where NAME is the name of the procedure to be defined, in this
  1693. case `Lpick'.  The next two arguments, MAXFACEVERTS and
  1694. MAXPATHLEN, give the sizes to be used for declaring two local
  1695. variable arrays in the body of the procedure.  These arrays are for
  1696. storing information about the picked face and the picked primitive's
  1697. path.  In this module we don't care about this information (it
  1698. corresponds to some of the things masked out by the `nil''s in the
  1699. `interest' call above) so we specify 1, the minimum allowable, for
  1700. both of these.  The last argument, BLOCK, is a block of code to be
  1701. executed when a pick event occurs.  The BLOCK should be delimited
  1702. by curly braces.  The code in your BLOCK should not include
  1703. any `return' statements.
  1704.  
  1705. `PICKFUNC' declares certain local variables in the body of the
  1706. procedure.  When the module receives a `(pick ...)' statement
  1707. from Geomview, the procedure assigns values to these variables based on
  1708. the information in the `pick' call.  (Variables corresponding to
  1709. `nil''s in the `(interest (pick ...))' are not given
  1710. values.)
  1711. These variables are:
  1712.  
  1713. `char *coordsys;'
  1714.      A string specifying the coordinate system in which coordinates are
  1715.      given.  In this example, this will always be `world' because
  1716.      of the `interest' call above.
  1717.  
  1718. `char *id;'
  1719.      A string specifying the name of the picked geom.
  1720.  
  1721. `HPoint3 point; int pn;'
  1722.      `point' is an `HPoint3' structure giving the coordinates of
  1723.      the picked point.  `HPoint3' is a homogeneous point coordinate
  1724.      representation equivalent to an array of 4 floats.  `pn' tells how
  1725.      many coordinates have been written into this array; it will always be
  1726.      either 0 or 4.  A value of zero means no point was picked, i.e. the user
  1727.      clicked the right mouse button while the cursor was not pointing at a
  1728.      geom.
  1729.  
  1730. `HPoint3 vertex; int vn;'
  1731.      `vertex' is an `HPoint3' structure giving the coordinates of
  1732.      the picked vertex, if the pick point was near a vertex.  `vn' tells
  1733.      how many coordinates have been written into this array; it will always
  1734.      be either 0 or 4.  A value of zero means the pick point was not near a
  1735.      vertex.
  1736.  
  1737. `HPoint3 edge[2]; int en;'
  1738.      `edge' is an array of two `HPoint3' structures giving the
  1739.      coordinates of the endpoints of the picked edge, if the pick point was
  1740.      near an edge.  `en' tells how many coordinates have been written
  1741.      into this array; it will always be either 0 or 8.  A value of zero means
  1742.      the pick point was not near an edge.
  1743.  
  1744.  
  1745. In this example module, the remaining variables will never be given
  1746. values because their values in the `interest' statement were
  1747. specified as `nil'.   
  1748.  
  1749.  
  1750. `HPoint3 face[MAXFACEVERTS]; int fn;'
  1751.      `face' is an array of MAXFACEVERTS `HPoint3''s;
  1752.      MAXFACEVERTS is the value specified in the `PICKFUNC' call.
  1753.      `face' gives the coordinates of the vertices of the picked face.
  1754.      `fn' tells how many coordinates have been written into this array;
  1755.      it will always be a multiple of 4 and will be at most
  1756.      4*MAXFACEVERTS.  A value of zero means the pick point was not near
  1757.      a face.
  1758.  
  1759. `HPoint3 ppath[MAXPATHLEN; int ppn;'
  1760.      `ppath' is an array of MAXPATHLEN `int''s;
  1761.      MAXPATHLEN is the value specified in the `PICKFUNC' call.
  1762.      `ppath' gives the path through the OOGL heirarchy to the picked
  1763.      primitive.  `pn' tells how many integers have been written into
  1764.      this array; it will be at most MAXPATHLEN.  A path of {3,1,2},
  1765.      for example, means that the picked primitive is "subobject number 2
  1766.      of subobject number 1 of object 3 in the world".
  1767.  
  1768. `int vi;'
  1769.      `vi' gives the index of the picked vertex in the picked primitive,
  1770.      if the pick point was near a vertex.
  1771.  
  1772. `int ei[2]; int ein'
  1773.      The `ei' array gives the indices of the endpoints of the picked
  1774.      edge, if the pick point was near a vertex.  `ein' tells how many
  1775.      integers were written into this array.  It will always be either 0 or 2;
  1776.      a value of 0 means the pick point was not near an edge.
  1777.  
  1778. `int fi;'
  1779.      `fi' gives the index of the picked face in the picked primitive, if
  1780.      the pick point was near a face.
  1781.  
  1782.  
  1783. The `handle_pick' procedure actually does the work of dealing with
  1784. the pick event.  It begins by normalizing the homogeneous coordinates
  1785. passed in as arguments so that we can assume the fourth coordinate is 1.
  1786. It then sends gcl commands to define the `pick' object to be
  1787. whatever is appropriate for the kind of pick recieved.  See *Note OOGL File Formats::, and *Note GCL::, for an explanation of the
  1788. format of the data in these commands.
  1789.  
  1790. The main program, at the bottom of the file, first calls
  1791. `Initialize()'.  Next, the call to `LakeDefine' defines the
  1792. `Lake' that the lisp library will use.  A `Lake' is a
  1793. structure that the lisp library uses internally as a type of
  1794. communiation vehicle.  (It is like a unix stream but more general, hence
  1795. the name.)  This call to `LakeDefine' defines a `Lake'
  1796. structure for doing I/O with `stdin' and `stdout'.  The third
  1797. argument to `LakeDefine' should be `NULL' for external modules
  1798. (it is used by Geomview).  Finally, the program enters its main loop
  1799. which parses and evaluates expressions from standard input.
  1800.  
  1801. 
  1802.